﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Xml;
using System.IO;
namespace GameVLTK
{
    public class Map : VisibleGameEntity
    {
        #region Thuộc tính
        //Vẽ background 
        private static TiledLayer _BackGround;

        public static TiledLayer BackGround
        {
            get { return _BackGround; }
            set { _BackGround = value; }
        }

        //Chứa các object đang tồn tại trên Map bao gồm: Player, Killer, NPC, vật thể trên Map.
        public static List<VisibleGameEntity> ForeGround = new List<VisibleGameEntity>();

        //Số dòng, số cột của ma trận
        static private int _nRows;

        static public int nRows
        {
            get { return _nRows; }
            set { _nRows = value; }
        }
        static private int _nCols;

        static public int nCols
        {
            get { return _nCols; }
            set { _nCols = value; }
        }

        //Mảng dùng để kiểm tra collision
        static private int[,] _CellMatrix;

        static public int[,] CellMatrix
        {
            get { return _CellMatrix; }
            set { _CellMatrix = value; }
        }

        //Kích thước Cell trong Map
        static private int _CellWidth;

        static public int CellWidth
        {
            get { return _CellWidth; }
            set { _CellWidth = value; }
        }
        static private int _CellHeight;

        static public int CellHeight
        {
            get { return _CellHeight; }
            set { _CellHeight = value; }
        }
        /*DANH SÁCH CÁC UNIT TRONG GAME */

        //Nhân vật chính trong game
        private static Player _Player;

        public static Player Player
        {
            get { return _Player; }
            set { _Player = value; }
        }

        //Danh sách các NPC 
        private static NPCManager _NPCs;

        public static NPCManager NPCs
        {
            get { return _NPCs; }
            set { _NPCs = value; }
        }

        //Danh sách Killer
        static private KillerManager _Killers;

        static public KillerManager Killers
        {
            get { return _Killers; }
            set { _Killers = value; }
        }

        //Danh sách Skill
        public static PrototypeSkills PrototypeSkills;

        
        //Danh sách các vật phẩm do đối tượng phát sinh
        public static ProductionManager ProductionsManager;

      
        //Cửa hàng vật phẩm trong game
        public static PrototypeProductions PrototypeProductions;

        //Danh sách các aura
        public static PrototypeAuras PrototypeAuras;

        //Mouses
        private static MyMouse _Mouses;

        public static MyMouse Mouses
        {
            get { return Map._Mouses; }
            set { Map._Mouses = value; }
        }

        //Mini Map 
        private static MiniMap _MiniMap;

        public static MiniMap MiniMap
        {
            get { return Map._MiniMap; }
            set { Map._MiniMap = value; }
        }
       
        //Quản lý các Dot trên Mini Map
        public static List<UnitDot> Dots= new List<UnitDot>();

        //Quản lý các đối tượng tĩnh trên Map
        public static List<FixedObject> FixedObjects= new List<FixedObject>();

        //Load dữ liệu từ file Xml lên
        public static XmlDocument Doc;


        public static ContentManager Content;

        Texture2D txtTure;
        public static SpriteFont font;

        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="xmlFile"></param>
        public Map(ContentManager content, String xmlFile)
        {
            txtTure = content.Load<Texture2D>("Images/Collisions/collision");
            font = content.Load<SpriteFont>("Fonts/font");

            //Lưu lại conntent
            Content = content;

            //Load file Xml lên
            Doc= new XmlDocument();
            Doc.Load(xmlFile);

            XmlNode nMap = Doc.DocumentElement;
            
            //Lấy vị trí Top Left của Map
            this.TopLeft = new Vector2(float.Parse(nMap.Attributes["X"].Value),
                                             float.Parse(nMap.Attributes["Y"].Value));

            Global.TopLeft = this.TopLeft;

            //Đường dẫn đến thư mục chứa các cell cần lộp
            String pathToCell = nMap.Attributes["Path-Cells"].Value;

            //Kích thước Cell trong Map
            CellWidth = int.Parse(nMap.Attributes["Cell-Width"].Value);
            CellHeight = int.Parse(nMap.Attributes["Cell-Height"].Value);
             
            //Đường dẫn đến Data dữ liệu
            string fileName="";

            //  Khởi tạo Background
            InitTLBackGround(content, pathToCell, fileName);

            //Hiệu chỉnh lại kích thước của Cell trong phần kiểm tra Collision
            CellWidth = Global.CELL_WIDTH;
            CellHeight = Global.CELL_HEIGH;

            // Khởi tạo Foreground
            InitTLForeGround(content, pathToCell);

            // Khởi tạo Collison
            InitTLCollision();

            // Khởi tạo Shop Production
            PrototypeProductions = new PrototypeProductions(content, Doc);

            //Khởi tạo Production Manager
            ProductionsManager = new ProductionManager();

            //Khởi tạo danh sách Skill
            PrototypeSkills = new PrototypeSkills(content, Doc);

            //Khởi tạo danh sách Aura
            PrototypeAuras = new PrototypeAuras(content, Doc);

            // Khởi tạo Player
            Player = new Player(content, Doc);
            ForeGround.Add(Player);

            // Khởi tạo NPCs
            NPCs = new NPCManager(content, Doc);

            // Khởi tạo Killers
            Killers = new KillerManager(content, Doc);

           //Khởi tạo Mouses
            Mouses = new MyMouse(content, Doc);

            //Khởi tạo MiniMap
            XmlNode nMiniMap = Doc.SelectSingleNode("//MINI_MAP");
            string path_MiniMap= nMiniMap.Attributes["Prefix"].Value;
            MiniMap = new MiniMap(content, path_MiniMap);
        }

        
        
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        public override void Update(GameTime gameTime)
        {
            //Update Mouse
            Mouses.Update(gameTime);

            //Update Background
            BackGround.Update(gameTime);

            // Update Player
            Player.Update(gameTime);

            //Update Killer
            Killers.Update(gameTime);

            //Update Production Manager
            ProductionsManager.Update(gameTime);

            // Update NPC
            NPCs.Update(gameTime);

            //Update Fixed Object
            for (int i = 0; i < FixedObjects.Count; i++)
                FixedObjects[i].Update(gameTime);

            //Sắp xếp các Object trên Map
            SortZ_Index();

        }

         
        /// <summary>
        /// 
        /// </summary>
        /// <param name="gameTime"></param>
        /// <param name="spriteBatch"></param>
        public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
           
            //Vẽ Background
            BackGround.Draw(gameTime, spriteBatch);

            //Vẽ Collision
            //DrawCollisionLayer(spriteBatch);

            //Vẽ Foreground
            for (int i = 0; i < ForeGround.Count; i++)
                ForeGround[i].Draw(gameTime, spriteBatch);

            //Vẽ MiniMap
            MiniMap.Draw(gameTime, spriteBatch);

            //Vẽ các Dot
            for (int i = 0; i < Dots.Count; i++)
                Dots[i].Draw(gameTime, spriteBatch);

            //Vẽ Mouse
            Mouses.Draw(gameTime, spriteBatch);

           
        }


        public override int OnEvent(Global.EVENTS eventID, object sender, object[] args)
        {
            int kq = 0;
            switch (eventID)
            {

                case Global.EVENTS.GM_MAP_TOPLEFT_CHANGED:
                    {
                        this.TopLeft += (Vector2)args[0];
                        break;
                    }
                default:
                    break;
            }

            return kq;
        }

        #region Khởi tạo thông tin Map
        /// <summary>
        /// (13,19)
        /// </summary>
        private void InitTLCollision()
        {
            XmlNode nCollision = Doc.SelectSingleNode("//COLLISION");
            LoadMatrixCollision(nCollision.Attributes["Path-Data"].Value);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="content"></param>
        /// <param name="pathToCell"></param>
        private void InitTLForeGround(ContentManager content, String pathToCell)
        {
            XmlNode nForeGround = Doc.SelectSingleNode("//FOREGROUND");
            int nFixedObject = nForeGround.ChildNodes.Count;

            //Các biến cần sử dụng để khởi tạo Fixed Objects
            Vector2 topleft = new Vector2();
            XmlNode nObj = null;
            int cellX = -1;
            int cellY = -1;
            int nTextures = 0;
            FixedObject obj = null;

            for (int i = 0; i < nFixedObject; i++)
            {
                nObj = nForeGround.ChildNodes[i];

                //Lấy vị trí Cell của obj
                cellX = int.Parse(nObj.Attributes["Cell-X"].Value) * 2;
                cellY = int.Parse(nObj.Attributes["Cell-Y"].Value) * 2;

                //Tính tọa độ thực tế cho obj
                topleft = Cell2Point(new Vector2(cellX, cellY));

                //Số lượng textures
                nTextures = int.Parse(nObj.Attributes["So_Luong"].Value);

               
                //Tạo obj
                obj = new FixedObject(content, Global.PATH_FOREGROUND + nObj.Attributes["Prefix"].Value,
                    nTextures, topleft);

                //Add obj
                ForeGround.Add(obj);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="content"></param>
        /// <param name="pathToCell"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private void InitTLBackGround(ContentManager content, String pathToCell, string fileName)
        {
            XmlNode nBackGround = Doc.SelectSingleNode("//BACKGROUND");

            //Đếm số loại cell
            int nTypeCell = nBackGround.ChildNodes.Count;
            String[] strCellTextures = new String[nTypeCell];
            for (int i = 0; i < nTypeCell; i++)
            {
                XmlNode nCell = nBackGround.ChildNodes[i];
                strCellTextures[i] = pathToCell + nCell.Attributes["Name"].Value;
            }

            fileName = nBackGround.Attributes["Path-Data"].Value;
            BackGround = new TiledLayer(fileName);
            BackGround.Init(content, strCellTextures, this.TopLeft, CellWidth,
                CellHeight);

        }
        
       
        /// <summary>
        /// 
        /// </summary>
        /// <param name="spriteBatch"></param>
        private void DrawCollisionLayer(SpriteBatch spriteBatch)
        {
            for (int i = 0; i < nRows; i++)
                for (int j = 0; j < nCols; j++)
                {

                    spriteBatch.Draw(txtTure, new Rectangle(j * CellWidth,
                                                            i * CellHeight, 32, 32),
                                                                Color.Red);

                    if (CellMatrix[i, j] > 0)
                    {
                        spriteBatch.Draw(txtTure, new Rectangle(j * CellWidth,
                                                            i * CellHeight, 32, 32),
                                                                Color.Yellow);


                        spriteBatch.DrawString(font, i.ToString(), new Vector2(j * CellWidth,
                                                          i * CellHeight), Color.White);
                    }


                }
        }

        /// <summary>
        /// Đọc dữ liệu từ file Text
        /// </summary>
        /// <param name="fileName"></param>
        private void LoadMatrixCollision(string fileName)
        {
            StreamReader sr = new StreamReader(fileName);

            string[] arr = sr.ReadLine().Split(' ');

            nRows = Convert.ToInt32(arr[0]);
            nCols = Convert.ToInt32(arr[1]);

            CellMatrix = new int[nRows, nCols];

            int i = 0;
            while (!sr.EndOfStream)
            {
                arr = sr.ReadLine().Split(' ');

                for (int j = 0; j < nCols; j++)
                {
                    CellMatrix[i, j] = Convert.ToInt32(arr[j]);  
                }

                i++;
            }
            sr.Close();
            
        }

        #endregion


        /// <summary>
        /// Chuyển cell ra tọa độ ở thế giới thực
        /// </summary>
        /// <param name="cell"></param>
        /// <returns></returns>
        public static Vector2 Cell2Point(Vector2 cell)
        {
            Vector2 screenPoint = new Vector2(0, 0);
            screenPoint.X = Global.TopLeft.Y + cell.Y * CellWidth;
            screenPoint.Y = Global.TopLeft.X + cell.X * CellHeight;

            return screenPoint;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="screenPoint"></param>
        /// <returns></returns>
        public static Vector2 Point2Cell(Vector2 screenPoint)
        {
            Vector2 cell = new Vector2(0, 0);
            cell.X = (int)(screenPoint.Y - Global.TopLeft.X) / CellHeight;
            cell.Y = (int)(screenPoint.X - Global.TopLeft.Y) / CellWidth;

            return cell;
        }

        


        /// <summary>
        /// Sort Z-Index của ForeGround theo thứ tự tăng dần của Z-Index
        /// </summary>
        private void SortZ_Index()
        {
            for (int i= 0; i< ForeGround.Count- 1; i++)
                for (int j = i + 1; j < ForeGround.Count; j++)
                    if (ForeGround[j].Z_Index < ForeGround[i].Z_Index)
                    {
                        VisibleGameEntity temp = ForeGround[i];
                        ForeGround[i] = ForeGround[j];
                        ForeGround[j] = temp;

                    }
                  
        }
    }
}
